package com.candy.common.interceptor;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.candy.common.enums.AdminErrorEnum;
import com.candy.common.properties.SystemProperties;
import com.candy.common.utils.Assert;
import com.candy.common.utils.CommonUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jodd.net.HttpMethod;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 自定义拦截器
 *
 * @author rong xi
 * @version 1.0
 * @date 2023/11/01 15:59
 */
@Slf4j
@Component
public class DsInterceptor implements HandlerInterceptor {
    /**
     * 防重复提交排除url
     */
    private final List<String> dsExcludes;
    private final SystemProperties systemProperties;
    private final RedissonClient redissonClient;

    /**
     * 路径匹配
     */
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    public DsInterceptor(SystemProperties systemProperties,RedissonClient redissonClient) {
        this.systemProperties = systemProperties;
        this.redissonClient = redissonClient;
        dsExcludes = Optional.ofNullable(systemProperties.getDsExcludes())
                .filter(StrUtil::isNotBlank)
                .map(Collections::singletonList)
                .orElse(new ArrayList<>());
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("请求路径:{}:{}",request.getMethod(),request.getRequestURI());
        //判断是否需要重复提交检查
        if(systemProperties.getDsEnabled() && needDsCheck(request)){
            //判断本次请求时间-上次请求时间是否<间隔
            String requestKey = CommonUtil.getRequestIp(request) + "_" + request.getMethod() + "_" + request.getRequestURI();
            RLock lock = redissonClient.getLock(requestKey);
            boolean hasLock = lock.tryLock(0, systemProperties.getDsInterval(), TimeUnit.MILLISECONDS);
            Assert.isTrue(hasLock, AdminErrorEnum.OPERATE_TOO_FREQUENTLY);
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    /**
     * 检查此次请求是否需要防重复提交过滤器
     *
     * @param request 请求
     * @return 是否执行过滤
     */
    private boolean needDsCheck(HttpServletRequest request) {
        String url = request.getServletPath();
        String method = request.getMethod();
        // GET 不过滤
        if (method == null || HttpMethod.GET.name().equalsIgnoreCase(method) || HttpMethod.OPTIONS.name().equalsIgnoreCase(method)) {
            return false;
        }
        //任何一个为空 不过滤
        if (CollectionUtil.isEmpty(dsExcludes)) {
            return true;
        }

        for (String pattern : dsExcludes) {
            if (pathMatcher.match(pattern, url)) {
                return false;
            }
        }
        return true;
    }

}
